package com.zhang.boot.core.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhang.boot.core.constants.ApiConstant;
import com.zhang.boot.core.constants.ErrorEnum;
import com.zhang.boot.core.constants.RegularConstant;
import com.zhang.boot.core.entity.Menu;
import com.zhang.boot.core.entity.Role;
import com.zhang.boot.core.entity.User;
import com.zhang.boot.core.mapper.UserMapper;
import com.zhang.boot.core.service.MenuService;
import com.zhang.boot.core.service.RoleService;
import com.zhang.boot.core.service.UserService;
import com.zhang.boot.core.util.AssertUtil;
import com.zhang.boot.core.util.ServletUtils;
import com.zhang.boot.core.vo.LoginUser;
import com.zhang.boot.core.vo.router.MetaVo;
import com.zhang.boot.core.vo.router.RouterVo;
import com.zhang.boot.core.vo.user.UserInfoVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


@Service
@Transactional
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private final RoleService roleService;
    private final TokenService tokenService;
    private final MenuService menuService;

    @Override
    public User getByAccount(String username) {
        AssertUtil.notEmpty(username, ErrorEnum.ACCOUNT_ERROR);
        User user = null;
        if (username.matches(RegularConstant.PHONE)) {
            user = getByPhone(username);
        } else if (username.matches(RegularConstant.EMAIL)) {
            user = getByEmail(username);
        } else {
            user = getByUsername(username);
        }
        return user;
    }


    @Override
    public boolean checkAdmin(User user) {
        if (user == null) {
            return false;
        }
        Integer userId = user.getUserId();
        List<Role> roles = roleService.listByUserId(userId);
        if (CollUtil.isEmpty(roles)) {
            user.setAdmin(false);
            return false;
        } else {
            boolean admin = roles.stream().anyMatch(role -> ApiConstant.ADMIN.equalsIgnoreCase(role.getRoleKey()));
            user.setAdmin(admin);
            return admin;
        }
    }

    @Override
    public UserInfoVo getUserInfo() {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        User user = loginUser.getUser();
        Set<String> roleSet = new HashSet<>();
        if (user.isAdmin()) {
            roleSet.add(ApiConstant.ADMIN);
        } else {
            List<Role> roles = user.getRoles();
            if (CollUtil.isNotEmpty(roles)) {
                roleSet = roles.stream()
                        .map(Role::getRoleKey)
                        .collect(Collectors.toSet());
            }
        }
        Set<String> permissions = loginUser.getPermissions();
        return UserInfoVo.builder()
                .user(user)
                .roles(roleSet)
                .permissions(permissions)
                .build();
    }

    @Override
    public List<RouterVo> getRouters() {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        // 用户信息
        User user = loginUser.getUser();
        List<Menu> menus = menuService.listTreeByUser(user);
        List<RouterVo> routers = menuService.buildMenus(menus);
        return buildRouters();
    }

    /**
     *
     * @return
     */
    public List<RouterVo> buildRouters() {
        List<RouterVo> routers = new ArrayList<>();
        List<RouterVo> systemChildren = new ArrayList<>();
        RouterVo userRouter = RouterVo.builder()
                .componentName("user")
                .componentPath("system/user/index")
                .hidden(false)
                .meta(new MetaVo("用户管理", "user"))
                .name("User")
                .path("user")
                .fullPath("/system/user")
                .build();
        RouterVo roleRouter = RouterVo.builder()
                .componentName("role")
                .componentPath("system/role/index")
                .hidden(false)
                .meta(new MetaVo("角色管理", "peoples"))
                .name("Role")
                .path("role")
                .fullPath("/system/role")
                .build();
        systemChildren.add(userRouter);
        systemChildren.add(roleRouter);

        RouterVo systemRouter = RouterVo.builder()
                .hidden(false)
                .componentName("Layout")
                .componentPath("")
                .meta(new MetaVo("系统管理", "system"))
                .name("System")
                .path("/system")
                .fullPath("")
                .redirect("noRedirect")
                .children(systemChildren)
                .build();
        routers.add(systemRouter);
        List<RouterVo> articleChildren = new ArrayList<>();
        RouterVo editorRouter = RouterVo.builder()
                .componentName("listArticle")
                .componentPath("article/list/index")
                .hidden(false)
                .meta(new MetaVo("文章列表", "chart"))
                .name("ListArticle")
                .path("listArticle")
                .fullPath("/article/listArticle")
                .build();
        RouterVo addRouter = RouterVo.builder()
                .componentName("addArticle")
                .componentPath("article/add/index")
                .hidden(false)
                .meta(new MetaVo("添加文章", "chart"))
                .name("AddArticle")
                .path("addArticle")
                .fullPath("/article/addArticle")
                .build();

        RouterVo updateArticleRouter = RouterVo.builder()
                .componentName("updateArticle")
                .componentPath("article/update/index")
                .hidden(true)
                .meta(new MetaVo("编辑文章", "chart"))
                .name("UpdateArticle")
                .path("updateArticle")
                .fullPath("/article/updateArticle")
                .build();
        articleChildren.add(editorRouter);
        articleChildren.add(addRouter);
        articleChildren.add(updateArticleRouter);
        RouterVo articleRouter = RouterVo.builder()
                .hidden(false)
                .componentName("Layout")
                .componentPath("")
                .meta(new MetaVo("文章管理", "chart"))
                .name("Article")
                .path("/article")
                .fullPath("")
                .redirect("noRedirect")
                .children(articleChildren)
                .build();
        routers.add(articleRouter);
        return routers;
    }

    @Override
    public User getByUsername(String username) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username);
        return getOne(queryWrapper);
    }

    @Override
    public User getByPhone(String phone) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getMobile, phone);
        return getOne(queryWrapper);
    }

    @Override
    public User getByEmail(String email) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getEmail, email);
        return getOne(queryWrapper);
    }

}
